#if !defined(DEF_FUNDEP_HPP)
#define DEF_FUNDEP_HPP

#include <iostream>
#include <set>
//structure générique d'ensemble set<T> 
#include <vector>
//structure générique de tableau dynamique vector<T> 
#include <map>
//structure générique de tableau associatif map<T,U> 
#include <list>
//structure générique de liste chainée list<T>
#include <string>

using namespace std;

const string ARROW_STR="->";
//chaine constante pour afficher et lire les DFs

/*********** Ensembles d'attributs ********************************************/
typedef string att_t;
//un attribut

typedef set<att_t> data_t;
//un ensemble d'attributs
/******************************************************************************/

/************ Algorithmes pour les attributs (FOURNIS dans df.cpp) ************/
ostream& operator<<(ostream& out, const data_t& s);
//affiche un ensemble d'attributs sur la sortie 'out'

data_t load_atts(const string& s);
//lit un ensemble d'attributs depuis la chaine s
/******************************************************************************/


/**************** Dépendances Fonctionnelles (DF) *****************************/
struct df_t {
//une DF X -> Y est une paire d'ensembles d'attributs
    data_t _src;
    //sa partie gauche, la 'source' X
    data_t _dst;
    //sa partie droite, la 'destination' Y
    df_t(const data_t &lhs = data_t(), const data_t &rhs  = data_t()) : _src(lhs), _dst(rhs){}
    //le constructeur qui permet d'initialiser une structure de DF en passant en
    //paramètre ses deux arguments
};
/******************************************************************************/

/**************** Algorithmes pour les DF (FOURNIS dans df.cpp) ***************/
bool operator == (const df_t &lhs, const df_t &rhs);
//égalité entre DFs

bool operator < (const df_t &lhs, const df_t &rhs);
//pour comparer des DFs selon l'ordre lexicographique

ostream& operator<<(ostream& out, const df_t &f);
//pour afficher une DF sur la sortie 'out'

istream& operator>> (istream& in, df_t& f);
//lit une DF depuis l'entrée 'in'
/******************************************************************************/



/************************* Ensembles de DFs ***********************************/
typedef vector<df_t> dfs_t ;
//un ensemble de dépendances est modélisé par un tableau dynamique de DFs
/******************************************************************************/

/******** Algorithmes pour les ensembles de DFs (FOURNIS dans df.cpp) *********/
ostream& operator<<(ostream& out, const dfs_t &s);
//pour afficher un ensemble de DFs sur la sortie 'out'

void load_dfs(istream& in, dfs_t &s);
//lit  un ensemble de DFs depuis un flux 'in'

void load_dfs(const string &file, dfs_t &s);
//lit  un ensemble de DFs depuis un fichier

/******************************************************************************/


/*********** Structures d'indexation ******************************************/
typedef  map<att_t,list<size_t> > index_t;
//structure d'indexation : à chaque attribut on fait correspondre la liste des
//indices des DFs qui contiennent cet attribut en partie gauche

typedef  vector<size_t> count_t;
//pour chaque index de DFs, on enregistre le nombre d'attributs de sa partie
//gauche pour savoir quand elle est "déclenchable"

/******************************************************************************/



/****************** Algorithmes (A DEFINIR DANS algos.cpp) ********************/
data_t closure(const dfs_t &s, const data_t &x);
//calcule la fermeture d'un ensemble d'attributs vis-à-vis d'un ensemble de DFs
//avec l'algorithme naif. CET ALGORITHME EST FOURNI

data_t schema(const dfs_t& s);
//calcule l'ensemble des attributs qui apparaissent dans les DFs de s

bool models(const dfs_t &s, const df_t &f);
//détermine si un ensemble de DFs en implique logiquement une autre en utilisant
//l'algorithme de fermeture : F |= X -> Y si et seulement si Y est inclus dans
//X+, la fermeture de X par F.

bool key(const dfs_t& s,const data_t &x);
//détermine si l'ensemble x est une clef en utilisant schema et closure

count_t buildcount(const dfs_t &s);
//analyse l'ensemble de dfs s pour compter le nombre d'attributs de sa partie gauche

index_t buildindex(const dfs_t &s);
//analyse l'ensemble de dfs s pour construire l'index <attribut vers DF> associé
//qui correspont à l'index 'list' dans l'algorithme théorique


data_t closurelin(const dfs_t &s, const data_t &x, const index_t &idx);
//calcule la fermeture d'un attribut vis-à-vis d'un ensemble de DFs
//version linéaire : s'appuie sur un index crée via buildindex

/*
bool modelslin(const dfs_t &s, const df_t &f, const index_t &idx);
//détermine si un ensemble de DFs en implique logiquement une autre

dfs_t complete(const dfs_t& s);
//complète la partie droite de chaque DF par la fermeture de sa partie gauche

dfs_t redundancies(const dfs_t& s);
//supprimer chaque DFs redondante dans l'ensemble s
*/

/******************************************************************************/

/****************************** Jeux d'essai **********************************/

dfs_t generate(size_t n);
//génère un ensemble de DFs de la forme {n-1 -> n, n-2 -> n-1, ..., 0 -> 1}

/******************************************************************************/

#endif //DEF_FUNDEP_HPP
